namespace SimpleWebServices.Web.UI.Html
{
    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using SimpleWebServices;
    using SimpleWebServices.Xml;
    using Xunit;

    public sealed class NameFacts
    {
        [Fact]
        public void typedef()
        {
            Assert.True(new ObjectExpectations<Name>()
                .DerivesFrom<object>()
                .IsConcreteClass()
                .IsSealed()
                .NoDefaultConstructor()
                .Serializable()
                .Implements<IComparable>()
                .Implements<IComparable<Name>>()
                .Implements<IEquatable<Name>>()
                .Result);
        }

        [Fact]
        public void ctor_string()
        {
            Assert.NotNull(new Name("a0-_:."));
        }

        [Fact]
        public void ctor_stringEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => new Name(string.Empty));
        }

        [Fact]
        public void ctor_stringNull()
        {
            Assert.Throws<ArgumentNullException>(() => new Name(null));
        }

        [Fact]
        public void ctor_SerializationInfo_StreamingContext()
        {
            Name expected = new Name("token");
            Name actual = null;

            using (Stream stream = new MemoryStream())
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(stream, new Name("token"));
                stream.Position = 0;
                actual = (Name)formatter.Deserialize(stream);
            }

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void prop_Token_get()
        {
            string expected = "token";
            string actual = new Name(expected).Token;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Token_set()
        {
            Name obj = new Name("a");

            string expected = "b";
            obj.Token = expected;

            string actual = obj.Token;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Token_setEmpty()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => new Name("token").Token = string.Empty);
        }

        [Fact]
        public void prop_Token_setNull()
        {
            Assert.Throws<ArgumentNullException>(() => new Name("token").Token = null);
        }

        [Fact]
        public void prop_Token_setValid()
        {
            Name obj = new Name("token");

            string expected = "a0-_:.";
            obj.Token = expected;

            string actual = obj.Token;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void prop_Token_setInvalidStartsWithNumber()
        {
            Assert.Throws<FormatException>(() => new Name("token").Token = "0token");
        }

        [Fact]
        public void prop_Token_setInvalidStartsWithSpecialCharacter()
        {
            Assert.Throws<FormatException>(() => new Name("token").Token = "@token");
        }

        [Fact]
        public void prop_Token_setInvalidStartsWithHyphen()
        {
            Assert.Throws<FormatException>(() => new Name("token").Token = "-token");
        }

        [Fact]
        public void prop_Token_setInvalidStartsWithUnderscore()
        {
            Assert.Throws<FormatException>(() => new Name("token").Token = "_token");
        }

        [Fact]
        public void prop_Token_setInvalidStartsWithColon()
        {
            Assert.Throws<FormatException>(() => new Name("token").Token = ":token");
        }

        [Fact]
        public void prop_Token_setInvalidStartsWithPeriod()
        {
            Assert.Throws<FormatException>(() => new Name("token").Token = ".token");
        }

        [Fact]
        public void opEquality_Name_Name()
        {
            Name obj = new Name("token");
            Name comparand = new Name("token");

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_Name_NameDiffers()
        {
            Name obj = new Name("a");
            Name comparand = new Name("b");

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Name_NameSame()
        {
            Name obj = new Name("token");
            Name comparand = obj;

            Assert.True(obj == comparand);
        }

        [Fact]
        public void opEquality_NameNull_Name()
        {
            Name obj = null;
            Name comparand = new Name("token");

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opEquality_Name_NameNull()
        {
            Name obj = new Name("token");
            Name comparand = null;

            Assert.False(obj == comparand);
        }

        [Fact]
        public void opInequality_Name_Name()
        {
            Name obj = new Name("token");
            Name comparand = new Name("token");

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_Name_NameDiffers()
        {
            Name obj = new Name("a");
            Name comparand = new Name("b");

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Name_NameSame()
        {
            Name obj = new Name("token");
            Name comparand = obj;

            Assert.False(obj != comparand);
        }

        [Fact]
        public void opInequality_NameNull_Name()
        {
            Name obj = null;
            Name comparand = new Name("token");

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opInequality_Name_NameNull()
        {
            Name obj = new Name("token");
            Name comparand = null;

            Assert.True(obj != comparand);
        }

        [Fact]
        public void opLesserThan_Name_Name()
        {
            Name obj = new Name("token");
            Name comparand = new Name("token");

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opLesserThan_Name_NameLesser()
        {
            Name obj = new Name("b");
            Name comparand = new Name("a");

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opLesserThan_NameLesser_Name()
        {
            Name obj = new Name("a");
            Name comparand = new Name("b");

            Assert.True(obj < comparand);
        }

        [Fact]
        public void opLesserThan_Name_NameNull()
        {
            Name obj = new Name("token");
            Name comparand = null;

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opLesserThan_NameNull_Name()
        {
            Name obj = null;
            Name comparand = new Name("token");

            Assert.True(obj < comparand);
        }

        [Fact]
        public void opLesserThan_NameNull_NameNull()
        {
            Name obj = null;
            Name comparand = null;

            Assert.False(obj < comparand);
        }

        [Fact]
        public void opGreaterThan_Name_Name()
        {
            Name obj = new Name("token");
            Name comparand = new Name("token");

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_NameGreater_Name()
        {
            Name obj = new Name("b");
            Name comparand = new Name("a");

            Assert.True(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_Name_NameGreater()
        {
            Name obj = new Name("a");
            Name comparand = new Name("b");

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_Name_NameNull()
        {
            Name obj = new Name("token");
            Name comparand = null;

            Assert.True(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_NameNull_Name()
        {
            Name obj = null;
            Name comparand = new Name("token");

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opGreaterThan_NameNull_NameNull()
        {
            Name obj = null;
            Name comparand = null;

            Assert.False(obj > comparand);
        }

        [Fact]
        public void opExplicit_string_Name()
        {
            string expected = "token";
            string actual = (string)new Name(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opExplicit_string_NameNull()
        {
            string expected = null;
            string actual = (string)(null as Name);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opExplicit_Name_string()
        {
            string token = "token";

            Name expected = new Name(token);
            Name actual = (Name)token;

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void opExplicit_Name_stringEmpty()
        {
            Name obj = null;

            Assert.Throws<ArgumentOutOfRangeException>(() => (Name)(obj = string.Empty));
        }

        [Fact]
        public void opExplicit_Name_stringNull()
        {
            string token = null;

            Name expected = null;
            Name actual = (Name)token;

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void opImplicit_string_Name()
        {
            string expected = "token";
            string actual = new Name(expected);

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opImplicit_string_NameNull()
        {
            string expected = null;
            string actual = null as Name;

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void opImplicit_Name_string()
        {
            string token = "token";

            Name expected = new Name(token);
            Name actual = token;

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void opImplicit_Name_stringEmpty()
        {
            Name obj = null;

            Assert.Throws<ArgumentOutOfRangeException>(() => (obj = string.Empty));
        }

        [Fact]
        public void opImplicit_Name_stringNull()
        {
            string token = null;

            Name expected = null;
            Name actual = token;

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void op_Convert_DateTime()
        {
            Name expected = "cabaabchbbdjacibceiie";
            Name actual = Name.Convert("2010-01-27T11:39:02.8124884Z".ConvertTo<DateTime>());

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void op_Convert_DateTimeMaxValue()
        {
            Name expected = "jjjjbcdbcdfjfjjjjjjjj";
            Name actual = Name.Convert(DateTime.MaxValue);

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void op_Convert_DateTimeMinValue()
        {
            Name expected = "aaabababaaaaaa";
            Name actual = Name.Convert(DateTime.MinValue);

            Assert.Equal<Name>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_Name()
        {
            int expected = 1;
            int actual = new Name("token").CompareTo(null as Name);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_NameEqual()
        {
            Name obj = new Name("token");
            Name comparand = new Name("token");

            int expected = 0;
            int actual = obj.CompareTo(comparand);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_NameGreater()
        {
            Name obj = new Name("a");
            Name comparand = new Name("z");

            int expected = -25;
            int actual = obj.CompareTo(comparand);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_NameLesser()
        {
            Name obj = new Name("z");
            Name comparand = new Name("a");

            int expected = 25;
            int actual = obj.CompareTo(comparand);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_NameSame()
        {
            Name obj = new Name("token");

            int expected = 0;
            int actual = obj.CompareTo(obj);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_object()
        {
            int expected = 1;
            int actual = new Name("token").CompareTo(null as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectEqual()
        {
            Name obj = new Name("token");
            object comparand = new Name("token");

            int expected = 0;
            int actual = obj.CompareTo(comparand as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectGreater()
        {
            Name obj = new Name("a");
            object comparand = new Name("z");

            int expected = -25;
            int actual = obj.CompareTo(comparand as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectLesser()
        {
            Name obj = new Name("z");
            object comparand = new Name("a");

            int expected = 25;
            int actual = obj.CompareTo(comparand as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectSame()
        {
            Name obj = new Name("token");

            int expected = 0;
            int actual = obj.CompareTo(obj as object);

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_CompareTo_objectString()
        {
            Assert.Throws<ArgumentOutOfRangeException>(() => new Name("token").CompareTo("token" as object));
        }

        [Fact]
        public void op_Equals_NameEqual()
        {
            string token = "token";

            Name obj = new Name(token);
            Name comparand = new Name(token);

            Assert.True(obj.Equals(comparand));
        }

        [Fact]
        public void op_Equals_NameUnequal()
        {
            Name obj = new Name("a");
            Name comparand = new Name("b");

            Assert.False(obj.Equals(comparand));
        }

        [Fact]
        public void op_Equals_NameNull()
        {
            Assert.False(new Name("token").Equals(null as Name));
        }

        [Fact]
        public void op_Equals_NameSame()
        {
            Name obj = new Name("token");
            Name comparand = obj;

            Assert.True(obj.Equals(comparand));
        }

        [Fact]
        public void op_Equals_objectEqual()
        {
            string token = "token";

            Name obj = new Name(token);
            object comparand = new Name(token);

            Assert.True(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectUnequal()
        {
            Name obj = new Name("a");
            object comparand = new Name("b");

            Assert.False(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectNull()
        {
            Assert.False(new Name("token").Equals(null as object));
        }

        [Fact]
        public void op_Equals_objectSame()
        {
            Name obj = new Name("token");
            object comparand = obj;

            Assert.True(obj.Equals(comparand as object));
        }

        [Fact]
        public void op_Equals_objectString()
        {
            Assert.False(new Name("token").Equals("token" as object));
        }

        [Fact]
        public void op_GetHashCode()
        {
            Name obj = new Name("token");

            int expected = obj.ToString().GetHashCode();
            int actual = obj.GetHashCode();

            Assert.Equal<int>(expected, actual);
        }

        [Fact]
        public void op_ToSimpleLinkOfT()
        {
            XLink expected = new XLink
            {
                Href = "#token",
                Type = "simple"
            };
            XLink actual = new Name("token").ToSimpleLink<XLink>();

            Assert.Equal<XLink>(expected, actual);
        }

        [Fact]
        public void op_ToSimpleLinkOfT_string()
        {
            XLink expected = new XLink
            {
                Href = "#token",
                Title = "Example",
                Type = "simple"
            };
            XLink actual = new Name("token").ToSimpleLink<XLink>(expected.Title);

            Assert.Equal<XLink>(expected, actual);
        }

        [Fact]
        public void op_ToSimpleLinkOfT_stringNull()
        {
            XLink expected = new XLink
            {
                Href = "#token",
                Type = "simple"
            };
            XLink actual = new Name("token").ToSimpleLink<XLink>(null as string);

            Assert.Equal<XLink>(expected, actual);
        }

        [Fact]
        public void op_ToSimpleLinkOfT_stringEmpty()
        {
            XLink expected = new XLink
            {
                Href = "#token",
                Title = string.Empty,
                Type = "simple"
            };
            XLink actual = new Name("token").ToSimpleLink<XLink>(expected.Title);

            Assert.Equal<XLink>(expected, actual);
        }

        [Fact]
        public void op_ToString()
        {
            string expected = "token";
            string actual = new Name("token").ToString();

            Assert.Equal<string>(expected, actual);
        }

        [Fact]
        public void op_GetObjectData_SerializationInfoNull_StreamingContext()
        {
            StreamingContext context = new StreamingContext(StreamingContextStates.All);

            Assert.Throws<ArgumentNullException>(() => (new Name("token") as ISerializable).GetObjectData(null as SerializationInfo, context));
        }

        [Fact]
        public void op_GetObjectData_SerializationInfo_StreamingContext()
        {
            SerializationInfo info = new SerializationInfo(typeof(Name), new FormatterConverter());
            StreamingContext context = new StreamingContext(StreamingContextStates.All);

            string expected = "token";

            (new Name(expected) as ISerializable).GetObjectData(info, context);

            string actual = info.GetString("_token");

            Assert.Equal<string>(expected, actual);
        }
    }
}